feat(mock): emit msw handlers and faker factories as separate files in split modes - #3730
Conversation
…n split modes In split and tags-split modes the get<Op>ResponseMock factories were duplicated in <name>.msw.ts and <name>.faker.ts. Now the faker file is the single home of the factories and the msw file imports and re-exports them. MSW-only output is unchanged unless the new operationResponses: false flag is set on the msw generator entry (handlers only, undefined fallbacks).
📝 WalkthroughWalkthroughMSW and Faker mock generation now preserves full outputs, moves response factories into Faker files for split modes, and adds MSW imports and re-exports. A new ChangesMSW/Faker output wiring
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant SplitWriter
participant MockOutputHelpers
participant ImportBuilder
participant FakerFile
participant MswFile
SplitWriter->>MockOutputHelpers: collapse and flatten full outputs
MockOutputHelpers->>ImportBuilder: provide cross-file Faker imports
ImportBuilder->>MswFile: emit grouped imports
MswFile->>FakerFile: import response factories
MswFile->>MswFile: emit Faker re-exports
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/core/src/writers/generate-imports-for-builder.ts (1)
137-156: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd a delimiter to the
uniqueBykey to prevent collisions.When concatenating
nameandimportPath, it is safer to use a delimiter like|to avoid edge-case collisions (e.g.,name: 'Foo', importPath: '/bar'vsname: 'Fo', importPath: 'o/bar'). This also matches the pattern used elsewhere in the file.♻️ Proposed fix
const otherImportsMap = new Map<string, GeneratorImport[]>(); for (const imp of uniqueBy( imports.filter( (i): i is GeneratorImport & { importPath: string } => !!i.importPath, ), - (x) => x.name + x.importPath, + (x) => `${x.name}|${x.importPath}`, )) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/writers/generate-imports-for-builder.ts` around lines 137 - 156, Update the uniqueBy key in the otherImportsMap construction to concatenate imp.name and imp.importPath with a delimiter, matching the file’s existing key-building pattern and preventing ambiguous combinations from colliding.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/content/docs/reference/configuration/output.mdx`:
- Around line 635-636: Update the split and tags-split mode documentation to
qualify the Faker placement behavior: response factories move to the .faker file
only when the Faker output declares every factory referenced by MSW. Document
that otherwise factories remain in .msw, or become undefined when
operationResponses is false.
In `@packages/core/src/writers/mock-outputs.ts`:
- Around line 87-99: Prioritize the operationResponses-disabled rewrite in
mockOutputs before the fakerDeclaresAllReferenced branch so MSW handlers omit
response bodies even when Faker factories are moved; update
packages/core/src/writers/mock-outputs.ts lines 87-99 accordingly, and update
packages/core/src/writers/mock-outputs.test.ts lines 218-228 to expect undefined
instead of getPetResponseMock().
- Around line 154-164: Preserve runtime extensions for cross-file faker imports
generated by buildCrossFileFakerImports: update its call sites in
packages/core/src/writers/split-mode.ts (not shown) and
packages/core/src/writers/split-tags-mode.ts:387-394 to pass
getImportExtension(extension, output.tsconfig), or update
buildCrossFileFakerImports in packages/core/src/writers/mock-outputs.ts:154-164
to apply that extension before generateImportsForBuilder emits importPath.
Ensure Node16/NodeNext output uses paths such as ./pets.faker.js while other
modes retain their existing behavior.
---
Nitpick comments:
In `@packages/core/src/writers/generate-imports-for-builder.ts`:
- Around line 137-156: Update the uniqueBy key in the otherImportsMap
construction to concatenate imp.name and imp.importPath with a delimiter,
matching the file’s existing key-building pattern and preventing ambiguous
combinations from colliding.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c31d89b0-8d5d-4167-bf48-a43797cc60c8
⛔ Files ignored due to path filters (113)
samples/hono/hono-with-fetch-client/__snapshots__/next-app/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/hono/hono-with-fetch-client/next-app/app/gen/pets/pets.msw.tsis excluded by!**/gen/**samples/next-app-with-fetch/__snapshots__/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/next-app-with-fetch/app/gen/pets/pets.msw.tsis excluded by!**/gen/**samples/react-app-with-swr/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.msw.tsis excluded by!**/__snapshots__/**samples/react-app-with-swr/fetch-client/__snapshots__/endpoints/swaggerPetstore.msw.tsis excluded by!**/__snapshots__/**samples/react-app/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.msw.tsis excluded by!**/__snapshots__/**samples/react-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.msw.tsis excluded by!**/__snapshots__/**samples/react-query/custom-fetch/__snapshots__/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/react-query/custom-fetch/src/gen/pets/pets.msw.tsis excluded by!**/gen/**samples/svelte-query/basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.msw.tsis excluded by!**/__snapshots__/**samples/svelte-query/custom-fetch/__snapshots__/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/svelte-query/custom-fetch/src/gen/pets/pets.msw.tsis excluded by!**/gen/**samples/svelte-query/v6-custom-fetch/__snapshots__/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/svelte-query/v6-custom-fetch/src/gen/pets/pets.msw.tsis excluded by!**/gen/**samples/swr-with-effect/__snapshots__/endpoints/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/swr-with-effect/src/gen/endpoints/pets/pets.msw.tsis excluded by!**/gen/**samples/swr-with-zod/__snapshots__/endpoints/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/swr-with-zod/src/gen/endpoints/pets/pets.msw.tsis excluded by!**/gen/**samples/vue-query/custom-fetch/__snapshots__/pets/pets.msw.tsis excluded by!**/__snapshots__/**samples/vue-query/custom-fetch/src/gen/pets/pets.msw.tsis excluded by!**/gen/**samples/vue-query/vue-query-basic/__snapshots__/endpoints/petstoreFromFileSpecWithTransformer.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/angular/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/angular/tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/angular/tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/petstore-tags-split-mutator/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/petstore-tags-split-mutator/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/tags-split-shared-models/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/axios/tags-split-shared-models/stores/stores.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/default/index-mock-file-split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/default/issue-2206-msw-info-typing/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/default/issue-2998/documents/documents.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/default/issue-2998/requests/requests.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/default/override-mock/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/fetch/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/fetch/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/fetch/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/issue-3574-strict-mock-tags-split-fetch/pets/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/issue-3574-strict-mock-tags-split-multi-fetch/store/store/store.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/issue-3574-strict-mock-tags-split/pets/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-mock-path/mocks/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/endpoints.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/cat.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/catType.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/createPetsBody.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/createPetsParams.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/createPetsSort.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/dachshund.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/dachshundBreed.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/dog.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/dogType.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/error.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/index.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/labradoodle.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/labradoodleBreed.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/listPetsParams.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/listPetsSort.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/pet.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/petCallingCode.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/petCountry.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/petWithTag.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split-msw-handlers-only/model/pets.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-mock-path/mocks/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-mock-path/mocks/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/health/health.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/cat.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/catType.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/createPetsBody.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/createPetsParams.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/createPetsSort.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/dachshund.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/dachshundBreed.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/dog.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/dogType.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/error.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/index.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/labradoodle.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/labradoodleBreed.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/listPetsParams.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/listPetsSort.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/pet.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/petCallingCode.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/petCountry.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/petWithTag.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/model/pets.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-msw-handlers-only/pets/pets.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-per-generator-path/msw/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/mock/tags-split-per-generator-path/msw/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/react-query/importFromSubdirectory/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/react-query/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/react-query/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/react-query/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/svelte-query/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/svelte-query/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/svelte-query/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/swr/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/swr/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/swr/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/vue-query/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/vue-query/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/vue-query/split/endpoints.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/zod/petstore-tags-split/health/health.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/zod/petstore-tags-split/pets/pets.msw.tsis excluded by!**/__snapshots__/**tests/__snapshots__/zod/split/endpoints.msw.tsis excluded by!**/__snapshots__/**
📒 Files selected for processing (19)
docs/content/docs/reference/configuration/output.mdxpackages/core/src/types.tspackages/core/src/writers/generate-imports-for-builder.test.tspackages/core/src/writers/generate-imports-for-builder.tspackages/core/src/writers/mock-outputs.test.tspackages/core/src/writers/mock-outputs.tspackages/core/src/writers/split-mode.tspackages/core/src/writers/split-tags-mode.tspackages/core/src/writers/target-tags.tspackages/core/src/writers/target.tssamples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.tssamples/react-app-with-swr/fetch-client/src/api/endpoints/swaggerPetstore.msw.tssamples/react-app/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.tssamples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.tssamples/solid-start/basic/src/api/endpoints/petstore.msw.tssamples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.tssamples/vue-query/vue-query-basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.tstests/api-generation.spec.tstests/configs/mock.config.ts
| if (fakerDeclaresAllReferenced) { | ||
| return mockOutputs.map((m) => | ||
| m.type === OutputMockType.MSW | ||
| ? { ...m, implementation: { ...m.implementation, function: '' } } | ||
| : m, | ||
| ); | ||
| } | ||
|
|
||
| if (options.mswOperationResponses === false) { | ||
| const strippedHandler = mswEntry.implementation.handler.replaceAll( | ||
| RESPONSE_MOCK_CALL_RE, | ||
| ': undefined', | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Honor operationResponses: false before moving Faker factories.
When Faker declares the referenced factories, the first branch keeps the fallback calls, so handler-only mode still returns generated response bodies.
packages/core/src/writers/mock-outputs.ts#L87-L99: apply themswOperationResponses === falserewrite before the Faker-movement branch.packages/core/src/writers/mock-outputs.test.ts#L218-L228: expect the fallback to becomeundefined, notgetPetResponseMock().
This contradicts the PR objective that operationResponses: false omits response bodies.
📍 Affects 2 files
packages/core/src/writers/mock-outputs.ts#L87-L99(this comment)packages/core/src/writers/mock-outputs.test.ts#L218-L228
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/core/src/writers/mock-outputs.ts` around lines 87 - 99, Prioritize
the operationResponses-disabled rewrite in mockOutputs before the
fakerDeclaresAllReferenced branch so MSW handlers omit response bodies even when
Faker factories are moved; update packages/core/src/writers/mock-outputs.ts
lines 87-99 accordingly, and update
packages/core/src/writers/mock-outputs.test.ts lines 218-228 to expect undefined
instead of getPetResponseMock().
There was a problem hiding this comment.
I'm open to tweaking this, but this is working as intended right now. The idea is that operationResponses on the msw config controls if the msw files are supposed to include the factories. If faker is also configured that takes "precedence", and the responses are imported.
The responses can always be overridden, so I think this is the right choice, but again, ofc open to tweaking this.
There was a problem hiding this comment.
@ingvaldlorentzen, thanks for the clarification — that makes sense as a design choice. Since operationResponses on the MSW config is scoped to whether MSW itself defines the factories (not whether responses exist at all), letting Faker's factories take precedence when both are configured is a reasonable and consistent behavior, especially since callers can always override the response via overrideResponse. I'll withdraw this concern.
(=^・ω・^=) ノ understood, noted for next time
✏️ Learnings added
Learnt from: ingvaldlorentzen
Repo: orval-labs/orval PR: 3730
File: packages/core/src/writers/mock-outputs.ts:88-100
Timestamp: 2026-07-15T13:21:13.658Z
Learning: In `packages/core/src/writers/mock-outputs.ts`, `collapseMswFakerFullOutputs` intentionally gives Faker precedence over the MSW `operationResponses: false` setting: if a Faker output declares all `get<Op>ResponseMock` factories referenced by MSW handlers, those factories are moved/imported from Faker regardless of `mswOperationResponses`. The `mswOperationResponses === false` fallback-to-`undefined` rewrite only applies when Faker does not declare all referenced factories (e.g., Faker isn't configured, or Faker also has `operationResponses: false`). This is intended: the MSW `operationResponses` flag only controls whether MSW itself embeds the factories, not whether responses exist when Faker is available, since responses can always be overridden by callers.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
There was a problem hiding this comment.
Pull request overview
Adds a new MSW mock configuration option to avoid generating (and in split modes, duplicating) potentially huge faker response factories, while preserving existing import ergonomics in split outputs.
Changes:
- Introduces
operationResponseson the MSW mock generator config to allow “handlers only” output (fallback response becomesundefined) insplit/tags-split. - In
split/tags-splitwhen both MSW + Faker are configured, movesget<Op>ResponseMock*factories into the.fakerfile and has.mswfiles import + re-export them (so prior import paths keep working). - Updates tests, snapshots, and samples to reflect the new split output structure (imports/re-exports instead of inline factory declarations).
Reviewed changes
Copilot reviewed 132 out of 132 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/configs/mock.config.ts | Adds new split and tags-split configs exercising MSW “handlers-only” mode. |
| tests/api-generation.spec.ts | Updates assertions for “factories live in faker file” behavior (import + re-export from msw). |
| packages/core/src/writers/target.ts | Exposes mockOutputsFull so split writers can post-process function vs handler portions before flattening. |
| packages/core/src/writers/target-tags.ts | Same as above for tag-bucket targets; uses shared flattenMockOutput. |
| packages/core/src/writers/split-mode.ts | Collapses MSW/Faker outputs: either strip factories + import from faker, or strip factories + replace fallback with undefined when operationResponses: false. |
| packages/core/src/writers/split-tags-mode.ts | Same logic as split-mode, applied per-tag; adds cross-file faker imports + re-exports in .msw outputs. |
| packages/core/src/writers/mock-outputs.ts | New helpers for: flattening full outputs, deciding MSW/Faker factory placement, extracting referenced response-mock names, and building cross-file imports/re-exports. |
| packages/core/src/writers/generate-imports-for-builder.ts | Groups explicit importPath imports by dependency so multiple cross-file imports become a single import statement. |
| packages/core/src/writers/generate-imports-for-builder.test.ts | Adds coverage for grouping/deduping importPath imports. |
| packages/core/src/types.ts | Adds operationResponses?: boolean to MswMockOptions. |
| docs/content/docs/reference/configuration/output.mdx | Documents MSW operationResponses and the MSW+Faker split-mode import/re-export behavior. |
| tests/snapshots/zod/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/vue-query/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/swr/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/svelte-query/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/react-query/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/react-query/importFromSubdirectory/endpoints.msw.ts | Snapshot update: msw imports + re-exports endpoint factories from .faker file. |
| tests/snapshots/mock/tags-split-per-generator-path/msw/health/health.msw.ts | Snapshot update: per-generator-path msw imports + re-exports from faker path. |
| tests/snapshots/mock/tags-split-msw-handlers-only/pets/pets.ts | New snapshot: generated client output for tags-split handlers-only fixture. |
| tests/snapshots/mock/tags-split-msw-handlers-only/pets/pets.msw.ts | New snapshot: tags-split MSW handlers-only output (fallback undefined). |
| tests/snapshots/mock/tags-split-msw-handlers-only/health/health.ts | New snapshot: generated client output for tags-split handlers-only fixture. |
| tests/snapshots/mock/tags-split-msw-handlers-only/health/health.msw.ts | New snapshot: text handler uses resolved override or undefined and returns text. |
| tests/snapshots/mock/tags-split-msw-handlers-only/model/* | New snapshots: model outputs for handlers-only fixture. |
| tests/snapshots/mock/tags-split-mock-path/mocks/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/mock/split-msw-handlers-only/endpoints.ts | New snapshot: split handlers-only fixture client output. |
| tests/snapshots/mock/split-msw-handlers-only/endpoints.msw.ts | New snapshot: split handlers-only MSW output (fallback undefined). |
| tests/snapshots/mock/split-msw-handlers-only/model/* | New snapshots: model outputs for split handlers-only fixture. |
| tests/snapshots/mock/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/mock/issue-3574-strict-mock-tags-split/pets/pets/pets.msw.ts | Snapshot update: strict-mock msw imports + re-exports response factories from .faker file; removes inline factories. |
| tests/snapshots/mock/issue-3574-strict-mock-tags-split-multi-fetch/store/store/store.msw.ts | Snapshot update: msw imports + re-exports response factories from .faker file; removes inline factories. |
| tests/snapshots/mock/issue-3574-strict-mock-tags-split-fetch/pets/pets/pets.msw.ts | Snapshot update: msw imports + re-exports response factories from .faker file; removes inline factories. |
| tests/snapshots/fetch/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/default/override-mock/endpoints.msw.ts | Snapshot update: msw imports + re-exports endpoint factories from .faker file instead of inlining. |
| tests/snapshots/default/issue-2998/requests/requests.msw.ts | Snapshot update: msw imports + re-exports request factories from .faker file. |
| tests/snapshots/default/issue-2998/documents/documents.msw.ts | Snapshot update: msw imports + re-exports document factories from .faker file. |
| tests/snapshots/default/issue-2206-msw-info-typing/endpoints.msw.ts | Snapshot update: msw imports + re-exports response factory from .faker file. |
| tests/snapshots/axios/tags-split-shared-models/stores/stores.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/axios/tags-split-shared-models/pets/pets.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/axios/petstore-tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/axios/petstore-tags-split-mutator/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| tests/snapshots/angular/tags-split/health/health.msw.ts | Snapshot update: msw imports + re-exports factories from .faker file. |
| samples/vue-query/vue-query-basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/vue-query/vue-query-basic/snapshots/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/vue-query/custom-fetch/src/gen/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/vue-query/custom-fetch/snapshots/pets/pets.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/swr-with-zod/src/gen/endpoints/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/swr-with-effect/src/gen/endpoints/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/swr-with-effect/snapshots/endpoints/pets/pets.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/svelte-query/v6-custom-fetch/src/gen/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/svelte-query/custom-fetch/src/gen/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/svelte-query/custom-fetch/snapshots/pets/pets.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/svelte-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/svelte-query/basic/snapshots/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/solid-start/basic/src/api/endpoints/petstore.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/react-query/custom-fetch/src/gen/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/react-query/custom-fetch/snapshots/pets/pets.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/react-query/basic/snapshots/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/react-app/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/react-app/snapshots/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/react-app-with-swr/fetch-client/src/api/endpoints/swaggerPetstore.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/react-app-with-swr/fetch-client/snapshots/endpoints/swaggerPetstore.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/react-app-with-swr/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/react-app-with-swr/basic/snapshots/endpoints/petstoreFromFileSpecWithTransformer.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/next-app-with-fetch/app/gen/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/next-app-with-fetch/snapshots/pets/pets.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
| samples/hono/hono-with-fetch-client/next-app/app/gen/pets/pets.msw.ts | Sample update: msw imports + re-exports factories from .faker file. |
| samples/hono/hono-with-fetch-client/snapshots/next-app/pets/pets.msw.ts | Snapshot update for sample: msw imports + re-exports factories from .faker file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/core/src/writers/generate-imports-for-builder.ts (1)
142-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInclude alias and import type in the deduplication key.
Currently, deduplicating
otherImportsby justnameandimportPathwill incorrectly merge imports that share these attributes but differ inalias,values(e.g., type vs. value imports), ordefault.Consider aligning this with how
schemaImportsare deduplicated by including those fields in the key to prevent unintended collisions.♻️ Proposed refactor
- (x) => `${x.name}|${x.importPath}`, + (x) => `${x.name}|${x.alias ?? ''}|${String(x.values)}|${String(x.default)}|${x.importPath}`,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/writers/generate-imports-for-builder.ts` at line 142, Update the otherImports deduplication key in the surrounding import-generation logic to include alias, values/import type, and default alongside name and importPath, matching the schemaImports key structure so distinct imports are not merged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/core/src/writers/generate-imports-for-builder.ts`:
- Line 142: Update the otherImports deduplication key in the surrounding
import-generation logic to include alias, values/import type, and default
alongside name and importPath, matching the schemaImports key structure so
distinct imports are not merged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 530897c2-3c84-437d-ae65-cdac4b415c81
📒 Files selected for processing (6)
docs/content/docs/reference/configuration/output.mdxpackages/core/src/writers/generate-imports-for-builder.tspackages/core/src/writers/mock-outputs.test.tspackages/core/src/writers/mock-outputs.tspackages/core/src/writers/split-mode.tspackages/core/src/writers/split-tags-mode.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- docs/content/docs/reference/configuration/output.mdx
- packages/core/src/writers/split-mode.ts
- packages/core/src/writers/mock-outputs.test.ts
- packages/core/src/writers/split-tags-mode.ts
|
cc @jakiestfu |
|
@ingvaldlorentzen would you mind showing me a sample configuration that disables faker but leaves MSW? |
@orval/angular
@orval/axios
@orval/core
@orval/effect
@orval/fetch
@orval/hono
@orval/mcp
@orval/mock
orval
@orval/query
@orval/solid-start
@orval/swr
@orval/zod
commit: |
Yeah, all you need is to set mock: {
generators: [
{
operationResponses: false,
type: OutputMockType.MSW,
},
],
}, |
|
@jakiestfu just to clarify, if you define both msw and faker, the faker bodies are no longer inlined in the However, they are re-exported from the Hope that makes sense. Config e.g. with both: mock: {
generators: [
{
operationResponses: false, // Has no effect in this case
type: OutputMockType.MSW,
},
{
type: OutputMockType.FAKER,
},
],
},Edit: |
|
this LGTM |
This is a follow up to the changes made in #1832
We have a situation where an API spec has very large (recursive) models, when generating MSW handlers this causes the faker "factories" to become very large, making the generated code unwieldy and causing memory issues with our builds.
There are probably many ways we could go about fixing it, but since we never use the provided faker response bodies from Orval, we would like to omit them entirely.
Generating the handlers is still very convenient, we don't have to set up all the path handling, globs etc. but we always want to provide our own response bodies (which are generally custom made faker objects to more accurately reflect production-like data).
Anyways, this PR aims to provide this feature. If you set
operationResponsestofalsein the msw config, the handlers will be generated without any faker responses.When
operationResponsesis set totrue(default) and both msw and faker is configured in the mock config, the faker objects/factories, are now imported from the faker files (in split mode obviously) instead of being re-defined within the msw handlers.The other modes should behave the same as before, with the faker factories inlined with msw handlers when only msw is defined and
operationResponses: true(default). And of course with only faker defined, only the faker files are generated.There are _a lot _ of changes in this PR, but they are mostly sample and snapshot changes, since imports etc. change.
I'm new to contributing to Orval, and am not very familiar with the codebase. So I may very well have made mistakes here. I'll ofc gladly make any requested tweaks if wanted!
Summary by CodeRabbit
operationResponsesoption to control whether MSW outputs include per-operation response mock factories.operationResponsesis disabled, generated handler-only MSW output now omits per-operation response factories and correctly adjusts fallback behavior.operationResponses, including expected cross-file behavior.